﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using DevExpress.XtraBars;
using EastFantasy.EasyEngine.Public;
using Timer = System.Windows.Forms.Timer;

namespace EastFantasy.EasyEngine.UI
{
    public partial class Main : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        #region 声明变量

        /// <summary>
        /// 快捷键类
        /// </summary>
        private Hotkeys Hotkey { get; set; }

        /// 快捷键Insert,修改
        /// <summary>
        /// 快捷键Insert,修改
        /// </summary>
        private UInt32 _insert;

        /// 快捷键Delete,还原
        /// <summary>
        /// 快捷键Delete,还原
        /// </summary>
        private UInt32 _delete;

        /// 快捷键PageUp,快速代码+1
        /// <summary>
        /// 快捷键PageUp,快速代码+1
        /// </summary>
        private UInt32 _pageUp;

        /// 快捷键PageDown,快速代码-1
        /// <summary>
        /// 快捷键PageDown,快速代码-1
        /// </summary>
        private UInt32 _pageDown;

        /// 快捷键F12 代码2
        /// <summary>
        /// 快捷键F12 代码2
        /// </summary>
        private UInt32 _f12;

        /// 选择的进程
        /// <summary>
        /// 选择的进程
        /// </summary>
        private Process _process;

        /// 后台刷新更改的代码
        /// <summary>
        /// 后台刷新更改的代码
        /// </summary>
        private Thread _threadRefresh;

        /// 后台监控代码
        /// <summary>
        /// 后台监控代码
        /// </summary>
        private Timer _timer;

        /// <summary>
        /// 查询四字节类型
        /// </summary>
        private const int ByteSize = 1 << 2;

        private readonly byte[] _bytesWrite = new byte[ByteSize];

        /// Grid数据源
        /// <summary>
        /// Grid数据源
        /// </summary>
        private DataTable dtSource;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        public Main()
        {
            InitializeComponent();
        }

        #endregion

        #region 窗体载入

        /// <summary>
        /// 窗体载入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_Load(object sender, EventArgs e)
        {
            panelScan.Visible = false;
            panelModify.Visible = true;
            //注册快捷键
            Hotkey = new Hotkeys(this.Handle);
            _insert = Hotkey.RegisterHotkey(Keys.Insert, Hotkeys.KeyFlags.MOD_ALT);
            _delete = Hotkey.RegisterHotkey(Keys.Delete, Hotkeys.KeyFlags.MOD_ALT);
            _pageUp = Hotkey.RegisterHotkey(Keys.PageUp, Hotkeys.KeyFlags.MOD_ALT);
            _pageDown = Hotkey.RegisterHotkey(Keys.PageDown, Hotkeys.KeyFlags.MOD_ALT);
            _f12 = Hotkey.RegisterHotkey(Keys.F12, Hotkeys.KeyFlags.MOD_ALT);
            Hotkey.OnHotkey += new HotkeyEventHandler(OnHotkey);

            //后台每秒查询是否代码改变(待修改拦截api)
            _timer = new Timer();
            _timer.Interval = 1000;
            _timer.Enabled = true;
            _timer.Tick += new EventHandler(_timer_Tick);

            //数据源
            dtSource = new DataTable();
            dtSource.Columns.Add("Check", typeof (bool));
            dtSource.Columns.Add("Remark");
            dtSource.Columns.Add("Address");
            dtSource.Columns.Add("AddressCode");
            dtSource.Columns.Add("Code");
            dtSource.Columns.Add("Code2");
            dtSource.Columns.Add("IsSuccess");
            dtSource.Columns.Add("InitAddressCode");
            dtSource.Columns.Add("IsFirstSearch");
            dtSource.PrimaryKey = new DataColumn[] {dtSource.Columns["Address"]};
        }

        #endregion

        #region 选择进程

        /// <summary>
        /// 选择进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnProcess_ItemClick(object sender, ItemClickEventArgs e)
        {
            try
            {
                ChooseProcess process = new ChooseProcess();
                if (process.ShowDialog(this) == DialogResult.OK)
                {
                    _process = process.Process;
                    barStatus.Caption = "当前进程 : " + _process.ProcessName + " 创建时间: " +
                                        _process.StartTime.ToString("MM-dd HH:mm:ss");
                    _timer.Start();
                }
            }
            catch (Exception ex)
            {
                Message.Show(this, "操作失败", "操作失败，程序遇到错误。" + ex.Message);
            }
        }

        #endregion

        #region 修改进程

        /// <summary>
        /// 修改进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnModify_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (_process == null || _process.HasExited)
            {
                Message.Show(this, "修改失败", "无法找到进程,可能进程已结束!");
                return;
            }
            try
            {
                if (CheckSelect()) return;
                int result = WriteProcess("W");
                if (result < 1)
                    Message.Show(this, "更改成功", "所有代码均更改成功!");
                else
                    Message.Show(this, "更改失败", "部分代码更改失败,请参见红色部分!");
            }
            catch (Exception ex)
            {
                Message.Show(this, "操作失败", "程序错误:" + ex.Message);
            }
        }

        /// <summary>
        /// 检测是否有选中项
        /// </summary>
        /// <returns></returns>
        private bool CheckSelect()
        {
            //没有选中的值
            List<int> listSelectRowCount = new List<int>();
            for (int i = 0; i < gvResultView.RowCount; i++)
            {
                bool flag = Convert.ToBoolean(gvResultView.GetRowCellValue(i, "Check"));
                if (flag)
                {
                    listSelectRowCount.Add(i);
                }
            }
            if (listSelectRowCount.Count == 0)
            {
                Message.Show(this, "更改失败", "请选择一行进行更改!");
                return true;
            }
            return false;
        }

        #endregion

        #region 添加基址代码

        /// <summary>
        /// 添加基址代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (txtAddress.EditValue == null)
            {
                Message.Show(this, "添加失败", "请输入内存基址!");
                return;
            }
            if (txtNewCode.EditValue == null)
            {
                Message.Show(this, "添加失败", "请输入要修改的代码!");
                return;
            }
            if (txtNewCode2.EditValue == null)
            {
                txtNewCode2.EditValue = string.Empty;
            }
            //将代码添加到Grid
            if (!dtSource.Rows.Contains(txtAddress.EditValue.ToString().Trim()))
            {
                dtSource.Rows.Add(false, string.Empty, txtAddress.EditValue.ToString().Trim(), string.Empty,
                                  txtNewCode.EditValue.ToString().Trim(), txtNewCode2.EditValue.ToString().Trim(), "Y",
                                  string.Empty, "Y");
                gvResult.DataSource = dtSource;
            }
            else
            {
                Message.Show(this, "添加失败", "该基址已添加,无需重复添加!");
                return;
            }
        }

        #endregion

        #region 关闭进程,清空Grid

        /// <summary>
        /// 关闭进程,清空Grid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_ItemClick(object sender, ItemClickEventArgs e)
        {
            try
            {
                _process = null;
                barStatus.Caption = "EastFantasy";
                txtAddress.EditValue = string.Empty;
                txtNewCode.EditValue = string.Empty;
                gvResult.DataSource = null;
                Message.Show(this, "关闭成功!", "进程关闭成功,代码已还原!");
            }
            catch (Exception ex)
            {
                Message.Show(this, "关闭失败!", "进程关闭失败!" + ex.Message);
            }
        }

        #endregion

        #region 还原进程

        /// <summary>
        /// 还原进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRevert_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (_process == null || _process.HasExited)
            {
                Message.Show(this, "修改失败", "无法找到进程,可能进程已结束!");
                return;
            }
            try
            {
                if (CheckSelect()) return;

                int result = WriteProcess("R");
                if (result < 1)
                    Message.Show(this, "还原成功", "所有代码均还原成功!");
                else
                    Message.Show(this, "还原失败", "代码还原失败,请参见红色部分!");
            }
            catch (Exception ex)
            {
                Message.Show(this, "操作失败", "程序错误:" + ex.Message);
            }
        }

        #endregion

        #region 写入内存

        /// <summary>
        /// 写入内存
        /// </summary>
        /// <param name="type">W:写入/R:还原</param>
        /// <returns></returns>
        public int WriteProcess(string type)
        {
            //停止进程监视
            if (_threadRefresh != null && _threadRefresh.IsAlive)
            {
                _threadRefresh.Abort();
            }
            string code = string.Empty;
            switch (type)
            {
                case "W":
                    code = "Code";
                    break;
                case "R":
                    code = "InitAddressCode";
                    break;
                case "W2":
                    code = "Code2";
                    break;
            }
            //更改失败的值
            List<int> listErrorRowCount = new List<int>();
            for (int i = 0; i < gvResultView.RowCount; i++)
            {
                //要改变的代码
                long writeCode = Convert.ToInt64(gvResultView.GetRowCellValue(i, code));
                //要改变的基址
                int writeAddress = Convert.ToInt32(gvResultView.GetRowCellValue(i, "Address").ToString(), 16);
                //返回的值
                int outCode;
                //将数据写入byte数组中
                for (int j = 0; j < ByteSize; j++)
                {
                    _bytesWrite[j] = (byte) ((writeCode & (0x00000000000000FF << j*8)) >> j*8);
                }
                //如果返回的值和实际写入字节数一样提示成功
                if (Win32.WriteProcessMemory(_process.Handle, (IntPtr) writeAddress, _bytesWrite, ByteSize, out outCode))
                {
                    //如果值不相等,则更改失败,将行号添加到list
                    if (outCode != ByteSize)
                    {
                        gvResultView.SetRowCellValue(i, "IsSuccess", "N");
                        listErrorRowCount.Add(i);
                        //高亮显示更改失败的行
                        Invoke(new MethodInvoker(() => gvResultView.RowCellStyle += (gvResultView_RowCellStyle)));
                    }
                    else
                    {
                        gvResultView.SetRowCellValue(i, "IsSuccess", "Y");
                    }
                }
            }
            return listErrorRowCount.Count;
        }

        #endregion

        #region 更改行颜色

        /// <summary>
        /// 更改行颜色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void gvResultView_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventArgs e)
        {
            if (e.RowHandle < 0) return;
            bool isSuccess = gvResultView.GetRowCellValue(e.RowHandle, "IsSuccess").ToString().Equals("Y");
            if (!isSuccess)
                e.Appearance.BackColor = Color.Red;
        }

        #endregion

        #region 快捷键事件

        /// <summary>
        /// 快捷键事件
        /// </summary>
        /// <param name="hotkeyId"></param>
        private void OnHotkey(int hotkeyId)
        {
            if (_process == null || _process.HasExited)
            {
                Message.Show(this, "更改失败", "没有进程或者进程丢失,请选附加一个进程!");
                return;
            }
            if (CheckSelect()) return;

            if (gvResultView.RowCount == 0)
            {
                Message.Show(this, "更改失败", "没有要修改的代码,请先添加一个代码!");
                return;
            }
            if (hotkeyId == _insert)
            {
                int result = WriteProcess("W");
                if (result < 1)
                    Message.Show(this, "更改成功", "所有代码均更改成功!");
                else
                    Message.Show(this, "更改失败", "部分代码更改失败,请参见红色部分!");
            }
            else if (hotkeyId == _f12)
            {
                int result = WriteProcess("W2");
                if (result < 1)
                    Message.Show(this, "更改成功", "所有代码均更改成功!");
                else
                    Message.Show(this, "更改失败", "部分代码更改失败,请参见红色部分!");
            }
            else if (hotkeyId == _delete)
            {
                int result = WriteProcess("R");
                if (result < 1)
                    Message.Show(this, "还原成功", "所有代码均还原成功!");
                else
                    Message.Show(this, "还原失败", "代码还原失败,请参见红色部分!");
            }
            else if (hotkeyId == _pageUp)
            {
                int code = 0;
                for (int i = 0; i < gvResultView.RowCount; i++)
                {
                    code = Convert.ToInt32(gvResultView.GetRowCellValue(i, "Code"));
                    code++;
                    gvResultView.SetRowCellValue(i, "Code", code);
                }
                WriteProcess("W");
                Message.Show(this, "成功", "代码+1,当前代码:" + code);
            }
            else if (hotkeyId == _pageDown)
            {
                int code = 0;
                for (int i = 0; i < gvResultView.RowCount; i++)
                {
                    code = Convert.ToInt32(gvResultView.GetRowCellValue(i, "Code"));
                    if (code == 0)
                    {
                        Message.Show(this, "错误", "代码为0,不能再次减小!");
                        break;
                    }
                    code--;
                    gvResultView.SetRowCellValue(i, "Code", code);
                }
                WriteProcess("W");
                Message.Show(this, "成功", "代码-1,当前代码:" + code);
            }
        }

        #endregion

        #region 后台每秒刷新一次更改的代码

        private void _timer_Tick(object sender, EventArgs e)
        {
            if (_process == null || _process.HasExited)
                return;
            if (_threadRefresh != null && _threadRefresh.IsAlive)
            {
                _threadRefresh.Abort();
            }
            _threadRefresh = new Thread(new ThreadStart(() =>
                {
                    while (true)
                    {
                        if (gvResultView.RowCount > 0)
                        {
                            try
                            {
                                if (_process == null || _process.HasExited)
                                    barStatus.Caption = "进程丢失!";
                                for (int i = 0; i < gvResultView.RowCount; i++)
                                {
                                    string address = gvResultView.GetRowCellValue(i, "Address").ToString();
                                    string codeNow = gvResultView.GetRowCellValue(i, "AddressCode").ToString();
                                    int outCode = GetCodeByAddress(address);
                                    if (gvResultView.GetRowCellValue(i, "IsFirstSearch").ToString().Equals("Y"))
                                    {
                                        Invoke(new MethodInvoker(() =>
                                            {
                                                gvResultView.SetRowCellValue(i, "InitAddressCode", outCode);
                                                gvResultView.SetRowCellValue(i, "IsFirstSearch", "N");
                                            }));
                                    }
                                    if (codeNow != outCode.ToString())
                                    {
                                        Invoke(
                                            new MethodInvoker(
                                                () => { gvResultView.SetRowCellValue(i, "AddressCode", outCode); }));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Message.Show(this, "错误", "程序错误!" + ex.Message);
                            }
                        }
                        Thread.Sleep(1000);
                    }
                }));
            _threadRefresh.IsBackground = true;
            _threadRefresh.Start();
        }

        #endregion

        #region 根据基址查找代码

        /// <summary>
        /// 根据基址查找代码
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        private int GetCodeByAddress(string address)
        {
            int readValue = 0;
            int outCode;
            if (Win32.ReadProcessMemory(_process.Handle, (IntPtr) Convert.ToInt32(address, 16), _bytesWrite, ByteSize,
                                        out outCode))
            {
                if (outCode == ByteSize)
                {
                    readValue = _bytesWrite[ByteSize - 1];
                    for (int j = ByteSize, k = 2; j > 1; j--, k++)
                    {
                        readValue = readValue << 8;
                        readValue = readValue | _bytesWrite[ByteSize - k];
                    }
                }
            }
            return readValue;
        }

        #endregion

        #region 关闭时分离进程

        /// <summary>
        /// 关闭时分离进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_process != null)
                _process.Close();
        }

        #endregion

        #region 删除选中行

        /// <summary>
        /// 删除选中行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDelete_ItemClick(object sender, ItemClickEventArgs e)
        {
            for (int i = gvResultView.RowCount; i >= 0; i--)
            {
                bool flag = Convert.ToBoolean(gvResultView.GetRowCellValue(i, "Check"));
                if (flag)
                    gvResultView.DeleteRow(i);
            }
        }

        #endregion

        private void ribbon_SelectedPageChanged(object sender, EventArgs e)
        {
            switch (pageModify.Ribbon.SelectedPage.Name)
            {
                case "pageModify":
                    panelModify.Visible = true;
                    panelScan.Visible = false;
                    break;
                case "pageScan":
                    panelModify.Visible = false;
                    panelScan.Visible = true;
                    break;
            }
        }
    }
}